#include "cx_timer.h"

#define TASK_CONTINUE 0
#define TASK_REFRASH  1
#define TASK_ONESHOT  2

#define SW_CONTINUE   0
#define SW_REFRASH    1
#define SW_ONESHOT    2

#define item_t2timer(x) ((cx_software_timer_t *)(x))
#define timer2item(x) ((cx_slist_item_t*)(x))

#ifndef CX_LIB_DISABLE_TIMER_TIMESTAMP

#endif

cx_uint64_t cx_timer_get_tick(cx_sw_timer_interface_t *timer_itf)
{
    return (timer_itf->ticks);
}

int cx_sw_timer_regSoftwareTimer(cx_sw_timer_interface_t *timer_itf, cx_software_timer_t *sw_timer)
{
    int ret = 0;
    cx_slist_append(&(timer_itf->sw_timer_list), timer2item(sw_timer));
    return ret;
}

int cx_sw_timer_logoutSoftwareTimer(cx_sw_timer_interface_t *timer_itf, cx_software_timer_t *sw_timer)
{
    int ret = 0;
    if((cx_slist_item_delete(&(timer_itf->sw_timer_list), timer2item(sw_timer))) == CX_NULL)
    {
        ret = -1;
    }
    return ret;
}


#ifndef CX_LIB_DISABLE_TIMER_TIMESTAMP

unsigned int getTimestamp(cx_sw_timer_interface_t *timer_itf)
{
    return (timer_itf->ticks * timer_itf->StampsPerTick + timer_itf->ticks);
}
#endif

int cx_sw_timer_init(cx_sw_timer_interface_t *timer_itf)
{
    timer_itf->ticks = 0;
    timer_itf->sw_timer_list.head = CX_NULL;
    timer_itf->sw_timer_list.tail = CX_NULL;
    timer_itf->cur_sw_timer = item_t2timer(timer_itf->sw_timer_list.head);
    return 0;
}

static int cx_sw_timer_handler(cx_sw_timer_interface_t *timer_itf,cx_software_timer_t *sw_timer)
{
    int ret = SW_CONTINUE;
    if(sw_timer == CX_NULL)
    {
        ret = SW_REFRASH;
    }
    else if(sw_timer->trigger_tick <= (timer_itf->ticks))
    {
        sw_timer->cb_handler(sw_timer->args);
        sw_timer->trigger_tick = sw_timer->trigger_tick + sw_timer->gap;
        if(sw_timer->trigger_type == TriggerTypeOneShot)
        {
            ret = SW_ONESHOT;
            return ret;
        }
    }
    return ret;
}

void SoftHandler(cx_sw_timer_interface_t *timer_itf)
{
#define sw_cur_handler (timer_itf->cur_sw_timer)
    cx_software_timer_t *sw_bk_handler;
    int tmp;
    timer_itf->ticks ++;
    while((tmp = cx_sw_timer_handler(timer_itf,sw_cur_handler)) != SW_REFRASH)
    {
        if(tmp == SW_CONTINUE)
        {
            sw_cur_handler = item_t2timer(sw_cur_handler->next);
        }
        else if (tmp == SW_ONESHOT)
        {
            if(sw_cur_handler->next == CX_NULL)
            {
                sw_bk_handler = item_t2timer(timer_itf->sw_timer_list.head);
            }
            else
            {
                sw_bk_handler = item_t2timer(sw_cur_handler->next);
            }
            cx_sw_timer_logoutSoftwareTimer(timer_itf,sw_cur_handler);
            sw_cur_handler = sw_bk_handler;
        }
    }
    if (tmp == SW_REFRASH)
    {
        sw_cur_handler = item_t2timer(timer_itf->sw_timer_list.head);
    }
}
